#include <string>
#include <thread>
#include <algorithm>

#if defined __TIMER_OLD__
#    include "timer_old.cpp"
#else
#include "timer.hpp"
#include "misc.hpp"
using namespace wheels;
using namespace dm;

#if defined( __WIN32 ) || defined( __WIN64 ) || defined( WIN32 ) || defined( WINNT )
#    include "details/winTimer.hpp"
#else
#    include "details/linuxTimer.hpp"
#endif

CTimer :: CTimer():
	pt_imp__( new

#if defined( __WIN32 ) || defined( __WIN64 ) || defined( WIN32 ) || defined( WINNT )	
		  winTimer()
#elif defined( __LINUX__ )
		  linuxTimer()
#endif
	){}

CTimer :: CTimer( long ms , bool oneShot ):
	pt_imp__( new 
#if defined( __WIN32 ) || defined( __WIN64 ) || defined( WIN32 ) || defined( WINNT )	
		  winTimer( ms , oneShot )
#elif defined( __LINUX__ )
		  linuxTimer( ms , oneShot )
#endif
	){}

CTimer :: CTimer( std::function< void () > fun , long ms , bool oneShot ):
	pt_imp__( new
#if defined( __WIN32 ) || defined( __WIN64 ) || defined( WIN32 ) || defined( WINNT )	
		  winTimer( fun , ms , oneShot )
#elif defined( __LINUX__ )
		  linuxTimer( fun , ms , oneShot )
#endif										     
	){}

CTimer :: ~CTimer(){}

iTimer :: emErrCode
CTimer :: Start( long ms , bool oneShot )
{
	return pt_imp__->Start( ms , oneShot );
}

void CTimer :: SetOwner( std::function<void(  )> fun )
{
	pt_imp__->SetOwner( fun );
}

iTimer :: emErrCode
CTimer :: Stop(  )
{
	return pt_imp__->Stop();
}

bool CTimer :: IsRuning(  )
{
	return pt_imp__->IsRuning();
}

iTimer :: emErrCode
CTimer :: Reset()
{
	return pt_imp__->Reset();
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////

#if SINGLETON_TIMER
IMP_SINGLETON( orderedTimer );
#endif

orderedTimer ::
stTimerItem :: stTimerItem( uint64_t t , uint32_t id , bool one_shot ):
	m_id( id ), m_abs_tick( 0 ), m_rel_tick( t ), m_one_shot( one_shot ){}

orderedTimer ::
stTimerItem :: stTimerItem( uint64_t t , uint32_t id , std::shared_ptr< orderedTimer > mgr , bool one_shot )
	:m_id( id ), m_abs_tick( 0 ), m_rel_tick( t ) , pt_mgr__( mgr ) , m_one_shot( one_shot ){}


void orderedTimer ::
stTimerItem :: start( bool sw )
{
        std::unique_lock< std::mutex>  lck( pt_mgr__->m_mutex__ );
	if( sw ){
		pt_mgr__->start_timer__( shared_from_this() );
	}else{
		pt_mgr__->stop_timer__( shared_from_this() );
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
orderedTimer :: orderedTimer( long itval ):
	      pt_timer__( std::make_shared<CTimer>(
		  std::bind( &orderedTimer::timer_processor__ , this ), itval , false )
	      ),
	      m_itval__( itval ),
	    m_base_ticks__( 0 ),
	    m_base_id__(0)
{}

orderedTimer :: ~orderedTimer()
{
	if( pt_timer__ ){
		pt_timer__->Stop( );
	}	
}

void orderedTimer ::  timer_processor__()
{
	std::unique_lock< std::mutex >   lck( m_mutex__ );
	auto it = m_data__.begin();	
	if( (it != m_data__.end() ) && (m_base_ticks__.load() >= it->first) ){
		for( auto it1 = it->second.begin(); it1 != it->second.end(); it1 ++ ){
			// 调用回调函数执行通知操作
		        if( (*it1)->m_cb ){
			        (*it1)->m_cb( );
		        }
		    		       
		    // 如果是连续触发，则再开启计时器，否则停止计时器
			auto timer_ptr = *it1;
			if( !(*it1)->m_one_shot ){
				start_timer__( timer_ptr );
			}
		}
		m_data__.erase( it );
	}
	m_base_ticks__ ++;
}

void orderedTimer :: start_timer__( std::shared_ptr<stTimerItem> timer )
{
	uint64_t abs_tick = timer->m_rel_tick + m_base_ticks__.load();
	auto it = m_data__.find( abs_tick );
	
	if( it != m_data__.end() ){
		it->second.push_back( timer );
	}else{
		std::list< std::shared_ptr< stTimerItem > >  list;
		list.push_back( timer );
		m_data__.insert( std::make_pair( abs_tick , list ) );
	}
}

void orderedTimer :: stop_timer__( std::shared_ptr<stTimerItem> timer )
{

	auto it = m_data__.find( timer->m_abs_tick );

	if( it->second.size() <= 1 ){
		m_data__.erase( it );
		return;
	}
			
	for( auto it1 = it->second.begin(); it1 != it->second.end(); it1 ++ ){
	        if( (*it1)->m_id == timer->m_id ){
			it->second.erase( it1 );
			return;
		}
	}
}

std::shared_ptr< orderedTimer::stTimerItem >
orderedTimer :: createTimer( uint64_t relTick , bool oneShot  )
{
        uint64_t abs_tick = m_base_ticks__.load() + relTick;
	auto it = m_data__.find( abs_tick );
	
	m_base_id__ ++;
	auto timer = std::make_shared< stTimerItem >( relTick , m_base_id__.load() , shared_from_this() , oneShot );
	
	return timer;

}

void orderedTimer :: start( bool sw )
{
    if( sw ){
		pt_timer__->Start( m_itval__.load() );
    }else{
		pt_timer__->Stop();
	}
}

void orderedTimer :: erase( iterator it )
{
	m_data__.erase( it );
}
void orderedTimer :: erase( iterator b , iterator e )
{
	m_data__.erase( b , e );
}
